package com.szeldon.declatest.declaration.scenario.parts;

import java.util.List;

/**
 * Utility class with methods convenient when working with scenario parts.
 * 
 * @author szeldon
 * 
 */
public final class ScenarioPartsHelper {

    /**
     * Returns true if currentPart was added to at the end of list of parts. False otherwise.
     * 
     * @param currentPart
     *            Part to be checked whether can be added after beforePart.
     * 
     * @param listOfParts
     *            List of parts preceding currentPart.
     * @return
     */
    public static boolean tryAddingPartAfter(ScenarioPartDeclaration currentPart,
            List<ScenarioPartDeclaration> listOfParts) {

        boolean canBeAdded = false;

        // gets last element of list
        ScenarioPartDeclaration lastPart = null;
        if (listOfParts.size() > 0) {
            lastPart = listOfParts.get(listOfParts.size() - 1);
        }

        if (lastPart == null) {
            canBeAdded = true;
        } else {

            canBeAdded = canBeOneAfterAnother(lastPart.getPartType(), currentPart.getPartType());
        }

        if (canBeAdded) {
            listOfParts.add(currentPart);
        } else {
            throw new UnsupportedOperationException("Can't add " + currentPart.getPartType() + " after "
                    + lastPart.getPartType() + ".");
        }

        return canBeAdded;
    }

    private static boolean canBeAfterReturn(ScenarioPartsTypeEnum partType) {
        return false;
    }

    private static boolean canBeAfterEnd(ScenarioPartsTypeEnum partType) {
        return false;
    }

    private static boolean canBeAfterCheckpoint(ScenarioPartsTypeEnum partType) {
        return true;
    }

    /**
     * Returns true if onePart can be followed by otherPart. False otherwise.
     * 
     * @param onePart
     * @param otherPart
     * @return
     */
    public static boolean canBeOneAfterAnother(ScenarioPartsTypeEnum onePart, ScenarioPartsTypeEnum otherPart) {

        boolean canBeAdded = false;
        // checks if last part can be followed by current part
        switch (onePart) {
        case IF_PART: {
            canBeAdded = canBeAfterIf(otherPart);
            break;
        }
        case ELSE_PART: {
            canBeAdded = canBeAfterElse(otherPart);
            break;
        }
        case DO_SCENARIO_STEP_PART: {
            canBeAdded = canBeAfterDoScenarioStep(otherPart);
            break;
        }
        case ERROR_PART: {
            canBeAdded = canBeAfterError(otherPart);
            break;
        }
        case CHECKPOINT_PART: {
            canBeAdded = canBeAfterCheckpoint(otherPart);
            break;
        }
        case END_PART: {
            canBeAdded = canBeAfterEnd(otherPart);
            break;
        }
        case RETURN: {
            canBeAdded = canBeAfterReturn(otherPart);
            break;
        }
        }
        return canBeAdded;
    }

    /**
     * Checks whether given part type can be placed after "Error" part in scenario.
     * 
     * @param partType
     *            Part type to be checked.
     * @return Returns true, if part type can be placed after "Error". False otherwise.
     */
    public static boolean canBeAfterError(ScenarioPartsTypeEnum partType) {
        return false;
    }

    /**
     * Checks whether given part type can be placed after "DoScenarioStep" part in scenario.
     * 
     * @param partType
     *            Part type to be checked.
     * @return Returns true, if part type can be placed after "DoScenarioStep". False otherwise.
     */
    public static boolean canBeAfterDoScenarioStep(ScenarioPartsTypeEnum partType) {
        return true;
    }

    /**
     * Checks whether given part type can be placed after "Else" part in scenario.
     * 
     * @param partType
     *            Part type to be checked.
     * @return Returns true, if part type can be placed after "Else". False otherwise.
     */
    public static boolean canBeAfterElse(ScenarioPartsTypeEnum partType) {
        return true;
    }

    /**
     * Checks whether given part type can be placed after "If" part in scenario.
     * 
     * @param partType
     *            Part type to be checked.
     * @return Returns true, if part type can be placed after "If". False otherwise.
     */
    public static boolean canBeAfterIf(ScenarioPartsTypeEnum partType) {
        return true;
    }
}
